#include "../inc/skyString.h"
#include "../inc/skyStd.h"

namespace Sky
{
#define  IsStaticString(str)	(0 != (const_cast<String*>(str)->_len & 0x80000000))
#define  toStaticLength(len)	(len |= 0x80000000)
#define  StringLen(len)			(len&0x7fffffff)
//String::String( const String* str )
//{
//	if(IsStaticString(str))
//	{//static string
//		_ref = 0;
//		_str = str->_str;
//		_len = str->_len;
//		_size = str->_size;
//	}
//	else
//	{//dynamic string
//		_ref = 1;
//		_len = str->_len;
//
//		if(_len == -1)
//			return;
//		_str = (Char*)Memory::alloc(const_cast<String*>(str)->getLength() + 1);
//		Memory::copy(_str,str->_str,_len + 1);
//		_size = _len + 1;
//	}
//}

String::String( staticString& str, int len ) :_str(const_cast<Char*>(str._str))
{
	//Char* pstr = "abcde" , Char str[] = {"abc"};
	//don't need release memory
	_len = len == -1 ? getStringLength(_str) : len;
	_size = str._size;
	toStaticLength(_len);
}

String::String( dynamicString& str, int len ) :_str(const_cast<Char*>(str._str))
{
	//need release memory
	_len = len == -1 ? getStringLength(_str) : len;
	_size = str._size;
	_str = (Char*)Memory::alloc(_size);
	Memory::copy(_str,str._str,_len + sizeof(Char));
}

String::String( const Char* str , int size, int len):_str(const_cast<Char*>(str))
{
	_len = (len != -1) ? _len = len: -1;
	_size= (size != -1) ? _size = size : -1;
	toStaticLength(_len);
}

String::String( managedString& str, int len /*= -1*/ ) : _str(const_cast<Char*>(str._str))
{
	//need release memory
	_len = len == -1 ? getStringLength(str._str) : len;
	_size = str._size;
}

String::String( String& str ):_len(0),_str(vNull)
{
	*this = str;
}

StringPtr String::toString(StringPtr str)
{
	if(!str) str = this;
	else 
	{
		int sd = str->getSize();
		int sr = this->getLength() + sizeof(Char);
		Memory::copy(str->toCharString(),this->toCharString(),sd > sr ? sr : sd);
	}
	return str;
}

u32 String::getLength()
{
	if(_len == -1)
	{
		i32 l = getStringLength(_str);
		if(IsStaticString(this))
			_len = toStaticLength(l);
		else _len = l;
	}
	return _len & 0x7fffffff;
}



String::~String()
{
	clear();
}

Bool String::compare( const StringPtr& str1,const StringPtr& str2 )
{
	if(const_cast<StringPtr&>(str1)->getLength() != const_cast<StringPtr&>(str2)->getLength())
		return false;
	return compare(const_cast<StringPtr&>(str1)->toCharString(),const_cast<StringPtr&>(str2)->toCharString());
}

Bool String::compare( const Char* str1,const Char* str2 )
{
	return !skyStrcmp(str1,str2);
}

u32 String::getSize()
{
	return _size;
}

Void String::operator=(String& str )
{
	clear();
	//if(str.isExactKindOf(String::Class))
	{
		{//dynamic string
			_len = str.getLength();
			_size = _len + sizeof(Char);
			if(!IsStaticString(&str))
			{	
				_str = (Char*)Memory::alloc(_size);
				Memory::copy(_str,str._str,_size);
			}
			else
			{
				_str = str._str;
				toStaticLength(_len);
			}

		}
	}
}

Void String::clear()
{
	if(!(IsStaticString(this)) && _str)
		Memory::free(_str);
	_str = vNull;
	_len = -1;
	_size = 0;
}


Bool String::copyFrom( const Char* str, i32 len )
{
	if(len == (i32)-1)len = (i32)skyStrlen(str);
	if(len + 1 <= _size)
	{
		Memory::copy(_str,str,sizeof(Char)*(len + 1));
		if(IsStaticString(this))
		{
			_len = len;
			toStaticLength(_len);
		}
		else
			_len = len;
		return vTrue;
	}
	else
	{
		clear();
		_str = (Char*)Memory::clone(sizeof(Char)*(len + 1),str);
		if(_str)
		{
			_len = len;
			_size = sizeof(Char)*(len + 1);
			return vTrue;
		}
		else
			return vFalse;
	}
	return vFalse;
}

Char* String::toCharString() const
{
	return _str;
}

StringPtr StringBuilder::toString(String* str)
{
	//String::dynamcString p = 
	Char* p = (Char*)Memory::alloc(_totalLength + sizeof(Char));//new Char[_totalLength + 1];
	StringNode* node = _head;
	Char* pos = p;
	while(node)
	{
		Memory::copy(pos,node->str->toCharString(),node->str->getLength());
		pos += node->str->getLength();
		node = node->next;
	}
	p[_totalLength] = '\0';
	clear();
	StringPtr ptr;
	if(!str)
	{
		String::managedString s(p,_totalLength + sizeof(Char));
		ptr = skynew(String(s));
	}
	else
	{
		Memory::copy(str->toCharString(),p,str->getSize() > _totalLength + sizeof(Char) ? _totalLength + sizeof(Char) : str->getSize());
		ptr = str;
	}
	append(ptr);
	return ptr;
}

StringBuilder::~StringBuilder()
{
	clear();
}

void StringBuilder::clear()
{
	StringNode* node;
	while(_head)
	{
		node = _head->next;
		delete _head;
		_head = node;
	}
	_totalLength = 0;
}

StringBuilder* StringBuilder::append( StringPtr& str )
{
	StringNode* p = new StringNode();
	p->str = str;
	p->next = NULL;
	if(_head == NULL)
	{
		_head = p;
		_rear = p;
	}
	else
	{
		_rear->next = p;
		_rear = p;
	}
	_totalLength += str->getLength();
	return this;
}

StringBuilder* StringBuilder::append( String::staticString& str )
{
	StringPtr s = skynew (String(str));
	return append(s);
}

StringBuilder* StringBuilder::append( String::dynamicString& str )
{
	StringPtr s = skynew (String(str));
	return append(s);
}

StringBuilder* StringBuilder::append( const Char* str,int len )
{
	StringPtr s = skynew (String(str,len));
	return append(s);
}

StringBuilder::StringBuilder() :_head(NULL),_totalLength(0)
{

}

}
